package algebra;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;

public class FloatRange implements Comparable<FloatRange> {
	public	float	min = Float.NEGATIVE_INFINITY;
	public	float	max = Float.POSITIVE_INFINITY;
	
	public static final FloatRange ALL_NUMBERS = new FloatRange(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
	
	public FloatRange() {
		set(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
	}
	public FloatRange(float min, float max) { 
		set(min,max);
	}
	
	public float getDiff() {
		return max-min;
	}
	
	public void set(float min, float max) {
		if (min>max)
			set(max,min);
		else {
			this.min = min;
			this.max = max;
		}
	}
	public boolean contains(FloatRange X) {
		return (X.min >= this.min && X.max < this.max);
	}
	public boolean contains(float X) {
		return (X >= this.min && X < this.max);
	}
	
	public static final boolean hasIntersection(FloatRange A, FloatRange B) {
		// Make sure A.min <= B.min
		if (A.min > B.min)
			return hasIntersection(B,A);
	
		// Because we know B.max >= A.max if the next condition is true there is overlap
		return (A.max > B.min);
	}
	public static final FloatRange	getIntersection(FloatRange A, FloatRange B) {
		// This will return the intersection of two float ranges if they exist
		// If they do not exist (No Overlap) then null is returned
		if (A.min > B.min)
			return getIntersection(B,A);
	
		if (A.max > B.min) {
			return new FloatRange(B.min,Math.min(A.max,B.max));
		} else {
			return null;
		}
	}
	public static final ArrayList<FloatRange>	getDiff(FloatRange A, FloatRange B) {
		//
		// This will return an array list of float ranges that represent the difference between
		// two FloatRanges. A-B (Not the same as B-A!)
		//
		FloatRange				I 		= getIntersection(A,B);
		ArrayList<FloatRange>	results = new ArrayList<FloatRange>();
		
		if (I==null) {
			results.add(A);
		} else {
			if (A.min < I.min) {
				results.add(new FloatRange(A.min, I.min));
			}
			if (I.max < A.max) {
				results.add(new FloatRange(I.max, A.max));
			}
		}
		return results;
	}
	
	public String toString() {
		return "( " + Float.toString(min) + " , " + Float.toString(max) + " )";
	}
	
	public boolean equals(FloatRange R) {
		return (min == R.min && max==R.max);
	}
	
	@Override
	public int compareTo(FloatRange o) {
		return compareRanges(this,(FloatRange) o);
	}
	public static final int compareRanges(FloatRange A, FloatRange B) {
		if (A==null && B==null) return 0;
		if (A==null) return -1;
		if (B==null) return 1;
		if (A.min < B.min) return -1;
		if (A.min > B.min) return 1;
		if (A.max < B.max) return -1;
		if (A.max > B.max) return 1;
		return 0;
	}
	public static final void	printFloatRanges(String titleMessage, Collection<FloatRange> ranges) {
		System.out.println(stringFloatRanges(titleMessage, ranges));
	}
	public static final String	stringFloatRanges(String titleMessage, Collection<FloatRange> ranges) {
		Iterator<FloatRange>	itr	= ranges.iterator();
		String output = "";

		output += titleMessage + "\n";
		while(itr.hasNext()) {
			output += "   " + itr.next().toString() +"\n";
		}
		return output;
	}
	
	public static final LinkedList<FloatRange>			InitialFloatRangeCoverage(FloatRange F) {
		LinkedList<FloatRange>	list = new LinkedList<FloatRange>();
		list.add(F);
		return list;
	}
	public static final LinkedList<FloatRange>			OneGiantBlackHole() {
		LinkedList<FloatRange>	blackHole = new LinkedList<FloatRange>();
		blackHole.add(new FloatRange(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
		return blackHole;
	}
	public static final LinkedList<FloatRange>			FillHoles(LinkedList<FloatRange> currentHoles, FloatRange fillRange) {
		//
		// This will iterate over all the holes currently detected and check for the possible differences with fill
		// range and return a new hole list
		//
		Iterator<FloatRange>	itr = currentHoles.iterator();
		
		FloatRange				current = null;
		LinkedList<FloatRange>	newHoles = new LinkedList<FloatRange>();
		ArrayList<FloatRange>	diff = null;
		
		while(itr.hasNext()) {
			current			= itr.next();
			diff = FloatRange.getDiff(current, fillRange);
			newHoles.addAll(diff);
		}
		return newHoles;
	}
	public static final LinkedList<FloatRange>			FillAllHoles(LinkedList<FloatRange> initialHoles, LinkedList<FloatRange> allFills) {
		//
		// This basically takes one fill at a time and constantly plugs holes in starting with initialHoles until
		// all the fillRanges have been exhausted
		//
		Iterator<FloatRange>	itr = allFills.iterator();
		LinkedList<FloatRange>	currentHoles = initialHoles;
		
		while(itr.hasNext()) {
			currentHoles = FillHoles(currentHoles, itr.next());
		}
		
		return currentHoles;
	}

}
